package com.br.android.math.trigonometry.circle;

import java.text.DecimalFormat;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.Handler;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;

public class TrigonometricCircleActivity extends Activity {

    private boolean      rotateThreadRunning = false;
    private boolean      cancelRotateThread  = false;
    private Handler      handler             = new Handler();
    private boolean      isBtnPlus           = false;
    private boolean      showSin;
    private boolean      showCos;
    private boolean      showTg;
    private boolean      showNotableAngles;
    private CanvasThread thread;
    private float        strokeWidth2;
    private float        strokeWidth3;
    private float        strokeWidth4;
    private float        strokeWidth8;
    private int          textSizeFunctions;
    private int          textSizeArcs;
    private int          textSizeXY;
    private final int    colorCircle         = Color.WHITE;
    private final int    colorAxes           = Color.GRAY;
    private final int    colorReferenceLine  = Color.RED;
    private final int    colorCos            = Color.rgb(0, 0, 200);
    private final int    colorSin            = Color.rgb(0, 255, 0);
    private final int    colorTg             = Color.rgb(255, 255, 0);
    private final int    colorText           = Color.WHITE;
    private final int    colorBackground     = Color.BLACK;
    private int          circleBorder;
    private String       projecoesStr;
    private String       cossenoStr;
    private String       tanStr;
    private String       arcoStr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        // Full sreen para API < 11
        // getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        strokeWidth2 = dipsToPixels(2);
        strokeWidth3 = dipsToPixels(3);// referencia angular RED

        strokeWidth4 = dipsToPixels(4);// circulo unitario
        strokeWidth8 = dipsToPixels(8);// + e -
        textSizeFunctions = dipsToPixels(40);
        textSizeArcs = dipsToPixels(17);
        textSizeXY = dipsToPixels(25);
        circleBorder = dipsToPixels(2);

        // carrego textos conforme LOCALE do aparelho
        projecoesStr = getString(R.string.projecoes);
        cossenoStr = getString(R.string.cos);
        tanStr = getString(R.string.tg);
        arcoStr = getString(R.string.arco);

        setContentView(new Panel(this));
    }

    class Panel extends SurfaceView implements SurfaceHolder.Callback {
        private int     _radius, _radiusMin;
        private int     _degrees, _tgY, _lastTgY;
        private int     _arcsPositionX, _arcsPositionY, _arcsSpace;
        private int     lastDegrees = 0;
        private double  lastDegreeInRadian = 0, sen, cos, tg;
        private boolean _start             = true;
        private boolean tgDefined          = false;
        private RectF   btnPlus            = new RectF();
        private RectF   btnMinus           = new RectF();
        private RectF   btnSettings        = new RectF();
        private Point   centerPoint, circlePoint, touchPoint, lastCirclePoint = new Point();
        private Canvas  canvas;
        // rect increase size for tought
        private int     _squarePlus;

        @Override
        public void onDraw(Canvas canvas) {
            this.canvas = canvas;

            /* Inicio para setar variáveis única vez */
            if (_start) {
                /* Tamanho das fontes e posição -- Convert the dips to pixels */
                _arcsPositionX = canvas.getWidth() - dipsToPixels(170);
                _arcsPositionY = canvas.getHeight() - dipsToPixels(70);
                _arcsSpace = dipsToPixels(20);

                /* Centro do círculo */
                _radius = (canvas.getHeight() / 2) - circleBorder;
                centerPoint = new Point(_radius + circleBorder, _radius + circleBorder);// X deslocado para a esquerda
                _radiusMin = dipsToPixels(20);
                _squarePlus = _radius / 16;
                circlePoint = new Point(centerPoint.x + _radius, centerPoint.y);

                /* Linha inicial no angulo ZERO */
                lastCirclePoint = touchPoint = circlePoint;
                _tgY = centerPoint.y;
                setLastDegrees(0);
                _start = false;
            }

            drawEverything();
        }

        /* Renderiza todos os elementos da tela */
        private void drawEverything() {
            /* Para controlar as cores */
            Paint paint = new Paint();
            paint.setAntiAlias(true);

            /* Cor da tela de fundo */
            canvas.drawColor(colorBackground);

            /* Ângulos notáveis */
            drawAngles();

            /* Eixos X e Y de referencia */
            paint.setStrokeWidth(strokeWidth3);
            paint.setPathEffect(null);
            paint.setColor(colorAxes);
            canvas.drawLine(0, centerPoint.y, centerPoint.x * 2, centerPoint.y, paint); // X (+50 para deixar = ao recf)
            canvas.drawLine(centerPoint.x, 0, centerPoint.x, centerPoint.y * 2, paint); // Y

            /* X e Y nas retas */
            paint.setTextSize(textSizeXY);
            canvas.drawText("X", centerPoint.x + _radius + dipsToPixels(5), centerPoint.y + dipsToPixels(20), paint);
            canvas.drawText("Y", centerPoint.x + dipsToPixels(10), dipsToPixels(40), paint);

            /* Desenha os botões */
            drawButtons();

            /* Desenha o arco central para referência angular */
            RectF oval = new RectF();
            Paint arcPaint = new Paint();
            arcPaint.setColor(colorAxes);
            // arcPaint.setStrokeWidth(strokeWidth5);
            arcPaint.setStyle(Paint.Style.FILL);
            oval.set(centerPoint.x - _radiusMin, centerPoint.y - _radiusMin, centerPoint.x + _radiusMin, centerPoint.y + _radiusMin);
            canvas.drawArc(oval, 0, lastDegrees, true, arcPaint);

            /* Desenha a linha de referência angular */
            paint.setColor(colorReferenceLine);
            paint.setStrokeWidth(strokeWidth3);
            paint.setStyle(Paint.Style.STROKE);
            Path path = new Path();
            path.moveTo(centerPoint.x, centerPoint.y);
            path.lineTo(lastCirclePoint.x, lastCirclePoint.y);
            canvas.drawPath(path, paint);

            /* Define retangulo delimitando área válida de toque */
            RectF f = new RectF(centerPoint.x - _radius, 0, centerPoint.x + _radius + _squarePlus, centerPoint.y * 2);

            /** Mostra retangulo para desenvolvimento */
            // arcPaint.setColor(Color.WHITE);
            // arcPaint.setStyle(Paint.Style.STROKE);
            // canvas.drawRect(f, arcPaint);

            /*
             * Guarda somente o toque dentro da area valida para renderizar elementos
             */
            if (f.contains(touchPoint.x, touchPoint.y)) {
                lastCirclePoint = new Point();
                lastCirclePoint.x = circlePoint.x;
                lastCirclePoint.y = circlePoint.y;
                setLastDegrees(_degrees);
                _lastTgY = _tgY;
            }

            /* Projecões */
            drawProjections();

            /* Valores das funções */
            DecimalFormat df = new DecimalFormat("#.####");
            StringBuffer sin, cos, tg, deg;

            deg = new StringBuffer();
            sin = new StringBuffer(df.format(this.sen));
            cos = new StringBuffer(df.format(this.cos));
            tgDefined = lastDegrees != -270 && lastDegrees != -90;
            tg = new StringBuffer((tgDefined ? df.format(this.tg) : ""));

            /* Para os ângulos notáveis, representação em fração, padrao BR */
            defineNotableAngles(sin, cos, tg, deg);

            paint = new Paint();
            paint.setAntiAlias(true);
            paint.setTextSize(textSizeArcs);
            paint.setStrokeWidth(strokeWidth2);

            /* Valor do ângulo (arco) */
            // canvas.restore();
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(colorText);
            canvas.drawText(arcoStr + ": " + -lastDegrees + "° " + deg, _arcsPositionX, _arcsPositionY - _arcsSpace, paint);

            String arco = deg.length() != 0 ? deg.toString() : "(" + -lastDegrees + "°)";

            paint.setColor(colorSin);
            canvas.drawText(getString(R.string.sen) + " " + arco + ": " + sin, _arcsPositionX, _arcsPositionY + _arcsSpace, paint);

            paint.setColor(colorCos);
            canvas.drawText(cossenoStr + " " + arco + ": " + cos, _arcsPositionX, _arcsPositionY + 2 * _arcsSpace, paint);

            paint.setColor(colorTg);
            canvas.drawText(tanStr + " " + arco + ": " + tg, _arcsPositionX, _arcsPositionY + 3 * _arcsSpace, paint);

            /* Círculo unitário */
            paint.setColor(colorCircle);
            paint.setStrokeWidth(strokeWidth4);
            paint.setStyle(Paint.Style.STROKE);
            canvas.drawCircle(centerPoint.x, centerPoint.y, _radius, paint);

            /* Valores para desenvolvimento */
            // canvas.drawText("T:" + touchPoint.toString(), canvas.getWidth() -
            // 500, 500, paint);
            // canvas.drawText("C:" + circlePoint.toString(), canvas.getWidth()
            // -500, 530, paint);
            // canvas.drawText("rad: " + _lastRadDegrees, canvas.getWidth() -
            // 500, 440, paint);
            // Double x = centerPoint.x + _radius * Math.cos(_lastRadDegrees);
            // Double y = centerPoint.y + _radius * Math.sin(_lastRadDegrees);
            // canvas.drawText(" x: " + x.intValue() +" y: " + y.intValue() ,
            // canvas.getWidth() - 500, 470, paint);

        }

        /**
         * Toda ves q muda o angulo, jah calculo os valores das funcoes
         * 
         * @param lastDegrees
         */
        public void setLastDegrees(int lastDegrees) {
            this.lastDegrees = lastDegrees;
            this.lastDegreeInRadian = Math.toRadians(lastDegrees);
            this.sen = Math.sin(-1 * this.lastDegreeInRadian);
            this.cos = Math.cos(this.lastDegreeInRadian);
            this.tg = Math.tan(-1 * this.lastDegreeInRadian);
        }

        /**
         * Para os ângulos notáveis, valores em frações
         * 
         * @param sin
         * @param cos
         * @param tg
         * @param deg Criado em 29/08/2012
         */
        private void defineNotableAngles(StringBuffer sin, StringBuffer cos, StringBuffer tg, StringBuffer deg) {
            switch (-lastDegrees) {
            case 0:
                deg.replace(0, 10, "(0 rad)");
                cos.replace(0, 10, "1");
                sin.replace(0, 10, "0");
                tg.replace(0, 10, "0");
                break;
            case 30:
                deg.replace(0, 10, "(π/6 rad)");
                sin.replace(0, 10, "1/2");
                cos.replace(0, 10, "√3/2");
                tg.replace(0, 10, "√3/3");
                break;
            case 45:
                deg.replace(0, 10, "(π/4 rad)");
                sin.replace(0, 10, "√2/2");
                cos.replace(0, 10, "√2/2");
                tg.replace(0, 10, "1");
                break;
            case 60:
                deg.replace(0, 10, "(π/3 rad)");
                sin.replace(0, 10, "√3/2");
                cos.replace(0, 10, "1/2");
                tg.replace(0, 10, "√3");
                break;
            case 90:
                deg.replace(0, 10, "(π/2 rad)");
                cos.replace(0, 10, "0");
                sin.replace(0, 10, "1");
                tg.replace(0, 10, "ND");
                break;
            case 120: /* 60 */
                deg.replace(0, 10, "(2π/3 rad)");
                sin.replace(0, 10, "√3/2");
                cos.replace(0, 10, "-1/2");
                tg.replace(0, 10, "-√3");
                break;
            case 135: /* 45 */
                deg.replace(0, 10, "(3π/4 rad)");
                sin.replace(0, 10, "√2/2");
                cos.replace(0, 10, "-√2/2");
                tg.replace(0, 10, "-1");
                break;
            case 150: /* 30 */
                deg.replace(0, 10, "(5π/6 rad)");
                sin.replace(0, 10, "1/2");
                cos.replace(0, 10, "-√3/2");
                tg.replace(0, 10, "-√3/3");
                break;
            case 180:
                deg.replace(0, 10, "(π rad)");
                cos.replace(0, 10, "-1");
                sin.replace(0, 10, " 0");
                tg.replace(0, 10, " 0");
                break;
            case 210: /* 30 */
                deg.replace(0, 10, "(7π/6 rad)");
                sin.replace(0, 10, "-1/2");
                cos.replace(0, 10, "-√3/2");
                tg.replace(0, 10, " √3/3");
                break;
            case 225: /* 45 */
                deg.replace(0, 10, "(5π/4 rad)");
                sin.replace(0, 10, "-√2/2");
                cos.replace(0, 10, "-√2/2");
                tg.replace(0, 10, "1");
                break;
            case 240: /* 60 */
                deg.replace(0, 10, "(4π/3 rad)");
                sin.replace(0, 10, "-√3/2");
                cos.replace(0, 10, "-1/2");
                tg.replace(0, 10, " √3");
                break;
            case 270:
                deg.replace(0, 10, "(3π/2 rad)");
                cos.replace(0, 10, "0");
                sin.replace(0, 10, "-1");
                tg.replace(0, 10, "ND");
                break;
            case 300: /* 60 */
                deg.replace(0, 10, "(5π/3 rad)");
                sin.replace(0, 10, "-√3/2");
                cos.replace(0, 10, "1/2");
                tg.replace(0, 10, "-√3");
                break;
            case 315: /* 45 */
                deg.replace(0, 10, "(7π/4 rad)");
                sin.replace(0, 10, "-√2/2");
                cos.replace(0, 10, "√2/2");
                tg.replace(0, 10, "-1");
                break;
            case 330: /* 30 */
                deg.replace(0, 10, "(11π/6 rad)");
                sin.replace(0, 10, "-1/2");
                cos.replace(0, 10, "√3/2");
                tg.replace(0, 10, "-√3/3");
            }
        }

        /**
         * Renderiza as projeções Sin,Cos,Tg
         * 
         * @param paint Criado em 29/08/2012
         */
        private void drawProjections() {
            Paint paint = new Paint();
            Paint paintTraced = new Paint();
            paintTraced.setStrokeWidth(strokeWidth2);
            paintTraced.setColor(colorAxes);
            paintTraced.setPathEffect(new DashPathEffect(new float[] { 5, 5 }, 0));
            paint.setStrokeWidth(strokeWidth3);
            paint.setAntiAlias(true);
            paint.setColor(colorSin);

            if (showSin) {
                canvas.drawLine(centerPoint.x, centerPoint.y, centerPoint.x, lastCirclePoint.y, paint);
                canvas.drawLine(lastCirclePoint.x, lastCirclePoint.y, centerPoint.x, lastCirclePoint.y, paintTraced);
            }

            paint.setColor(colorCos);
            paint.setStrokeWidth(strokeWidth3);
            paint.setAntiAlias(true);

            if (showCos) {
                canvas.drawLine(centerPoint.x, centerPoint.y, lastCirclePoint.x, centerPoint.y, paint);
                canvas.drawLine(lastCirclePoint.x, lastCirclePoint.y, lastCirclePoint.x, centerPoint.y, paintTraced);
            }

            paint.setColor(colorTg);
            paint.setStrokeWidth(strokeWidth3);
            paint.setAntiAlias(true);

            if (showTg && tgDefined) {
                canvas.drawLine(centerPoint.x + _radius, centerPoint.y, centerPoint.x + _radius, _lastTgY, paint);
                canvas.drawLine(lastCirclePoint.x, lastCirclePoint.y, centerPoint.x + _radius, _lastTgY, paintTraced);
            }
        }

        /**
         * Renderiza os botões
         * 
         * @param paint Criado em 29/08/2012
         */
        private void drawButtons() {
            int bottom = dipsToPixels(87);
            int space = dipsToPixels(8);
            int left = canvas.getWidth() - dipsToPixels(84);
            int right = canvas.getWidth() - dipsToPixels(2);
            Paint txPaint = new Paint();
            txPaint.setColor(colorText);
            txPaint.setStyle(Paint.Style.FILL);
            txPaint.setAntiAlias(true);
            txPaint.setStrokeWidth(strokeWidth2);
            txPaint.setTextAlign(Align.CENTER);
            txPaint.setTextSize(dipsToPixels(25));

            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setColor(colorCircle);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(strokeWidth2);

            /* Botão + * */
            // txPaint.setTextSize(dipsToPixels(25));
            btnPlus = new RectF(left, space, right, bottom);
            canvas.drawRect(btnPlus, paint);
            txPaint.setColor(colorText);
            txPaint.setTextSize(textSizeFunctions);
            txPaint.setStrokeWidth(strokeWidth8);
            canvas.drawText("+", btnPlus.centerX(), btnPlus.centerY() + dipsToPixels(12), txPaint);

            /* Botão - * */
            btnMinus = new RectF(left, bottom + space, right, 2 * bottom);
            canvas.drawRect(btnMinus, paint);
            txPaint.setTextSize(textSizeFunctions);
            txPaint.setStrokeWidth(strokeWidth8);
            canvas.drawText("-", btnMinus.centerX(), btnMinus.centerY() + dipsToPixels(12), txPaint);

            /* Botão Projecoes * */
            btnSettings = new RectF(left - space - (right - left), space, left - space, bottom);
            canvas.drawRect(btnSettings, paint);
            txPaint.setTextSize(textSizeArcs - dipsToPixels(2));
            txPaint.setStrokeWidth(8);
            canvas.drawText(projecoesStr, btnSettings.centerX(), btnSettings.centerY(), txPaint);
        }

        /**
         * Renderiza os ângulos Calculo de X/Y pela equação do circulo paramétrica
         * 
         * @param canvas
         * @param paint Criado em 29/08/2012
         */
        private void drawAngles() {
            Paint paint = new Paint();
            paint.setAntiAlias(true);
            paint.setColor(colorAxes);
            paint.setStrokeWidth(strokeWidth2);

            /* Ângulos de 10° em 10° */
            paint.setPathEffect(new DashPathEffect(new float[] { 20, _radius - dipsToPixels(5) }, 20)); // _radius-8
            for (int i = 10; i < 360; i += 10) {
                int x = Double.valueOf(centerPoint.x + _radius * Math.cos(Math.toRadians(i))).intValue();
                int y = Double.valueOf(centerPoint.y + _radius * Math.sin(Math.toRadians(i))).intValue();
                this.canvas.drawLine(centerPoint.x, centerPoint.y, x, y, paint);
            }

            if (showNotableAngles) {
                /* 30° */
                paint.setPathEffect(new DashPathEffect(new float[] { 20, _radius - dipsToPixels(10) }, 20)); // _radius-20
                for (int i = 30; i < 360; i += 30) {
                    int x = Double.valueOf(centerPoint.x + _radius * Math.cos(Math.toRadians(i))).intValue();
                    int y = Double.valueOf(centerPoint.y + _radius * Math.sin(Math.toRadians(i))).intValue();
                    this.canvas.drawLine(centerPoint.x, centerPoint.y, x, y, paint);
                }

                /* 45° */
                paint.setPathEffect(new DashPathEffect(new float[] { 40, _radius - dipsToPixels(20) }, 40)); // _radius-30
                for (int i = 45; i < 360; i += 45) {
                    int x = Double.valueOf(centerPoint.x + _radius * Math.cos(Math.toRadians(i))).intValue();
                    int y = Double.valueOf(centerPoint.y + _radius * Math.sin(Math.toRadians(i))).intValue();
                    this.canvas.drawLine(centerPoint.x, centerPoint.y, x, y, paint);
                }
            }
        }

        /**
         * Chamado aos eventos de toque na tela
         */
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            touchPoint = new Point((int) event.getX(), (int) event.getY());

            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (btnSettings.contains(touchPoint.x, touchPoint.y)) {
                    showSin = !showSin;
                    showCos = !showCos;
                    showTg = !showTg;
                    showNotableAngles = !showNotableAngles;
                    break;
                }
                else
                    if (btnPlus.contains(touchPoint.x, touchPoint.y)) {
                        isBtnPlus = true;
                        onButtonDown();
                        break;
                    }
                    else
                        if (btnMinus.contains(touchPoint.x, touchPoint.y)) {
                            isBtnPlus = false;
                            onButtonDown();
                            break;
                        }
                doOnTouch(false);
                break;
            case MotionEvent.ACTION_MOVE:
                doOnTouch(false);
                /* Se mover para fora dos botões, para thread */
                if (!btnPlus.contains(touchPoint.x, touchPoint.y) || !btnMinus.contains(touchPoint.x, touchPoint.y)) {
                    stopRotateThread();
                }
                break;
            case MotionEvent.ACTION_UP:
                stopRotateThread();
                break;
            }
            return true;
        }

        private void doOnTouch(boolean isButton) {

            /* Se for o movimento no próprio círculo */
            if (!isButton) {
                /* calculo do angulo entre duas linhas */
                _degrees = angleBetween2Lines(centerPoint.x, centerPoint.y, centerPoint.x + _radius, centerPoint.y, touchPoint.x, touchPoint.y);

                calculateLinePositions(touchPoint.x, touchPoint.y);
                calculateLineTgValueY(circlePoint.x, circlePoint.y);
            }
            else { /* Senão são os botões +/- */
                /** Calcular X/Y pela equação do circulo */
                lastCirclePoint.x = Double.valueOf(centerPoint.x + _radius * this.cos).intValue();
                lastCirclePoint.y = Double.valueOf(centerPoint.y - _radius * this.sen).intValue();

                /* Correcao do ponto do circulo e TgY */
                calculateLineTgValueY(lastCirclePoint.x, lastCirclePoint.y);
                _lastTgY = _tgY;

            }
            this.invalidate();
        }

        /**
         * Calcula o valor de Y da linha Tangente Criado em 25/08/2012
         */
        private void calculateLineTgValueY(int x, int y) {
            Double B, K;

            K = (double) (x - centerPoint.x) / _radius;
            if (K != 0) {
                B = (y - centerPoint.y) / K;
                _tgY = centerPoint.y + B.intValue();
            }
            else {
                _tgY = -10000; // protecao (aproximação) para nao travar no
                               // infinito (angulo 90 e 270 graus)
            }
        }

        /**
         * Calcula a possicao X,Y da linha para ela ter um tamanho constante no circulo inteiro. Utilizando triangulos semelhantes Criado em 22/08/2012
         */
        private void calculateLinePositions(int x, int y) {
            int cx, cy, tx, ty;
            int a, b, R;
            Double c;

            cx = centerPoint.x; // centro do círculo
            cy = centerPoint.y;
            tx = x; // touchPoint.x; //ponto tocado na tela
            ty = y; // touchPoint.y;
            R = _radius; // lado 3 do triangulo 2

            a = tx - cx; // lado 1 do triangulo 1
            b = ty - cy; // lado 2 do triangulo 1
            c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2)); // lado 3 do
                                                            // triangulo 1

            final Double K = R / c;
            // pontos no circulo
            circlePoint.x = cx + (int) (K * a); // ponto do centro + (proporcao
                                                // para aumento * tamanho lado
                                                // triangulo 1)
            circlePoint.y = cy + (int) (K * b);
        }

        /**
         * Calcula o angulo entre as duas linhas Linha 1: (centerX,centerY) -> (x1,y1) Linha 2: (centerX,centerY) -> (x2,y2)
         * 
         * @param centerX
         * @param centerY
         * @param x1
         * @param y1
         * @param x2
         * @param y2
         * @return Criado em 17/08/2012
         */
        private int angleBetween2Lines(float centerX, float centerY, float x1, float y1, float x2, float y2) {
            double angle1 = Math.atan2(y1 - centerY, x1 - centerX);
            double angle2 = Math.atan2(y2 - centerY, x2 - centerX);

            double angle = Math.toDegrees(angle1 - angle2) * -1;

            // correcao pra retornar somente angulos negativos (para a rotação
            // ser feita no sentido anti-horario)
            Double a = angle > 0 ? angle - 360 : angle;
            return a.intValue();
        }

        /**
         * Verifica se os pontos estao dentro do circulo definido pelos pontos
         * 
         * @param x
         * @param y
         * @param circleCenterX
         * @param circleCenterY
         * @param circleRadius
         * @return Criado em 24/08/2012
         */
        @SuppressWarnings("unused")
        // inCircle(touchPoint.x, touchPoint.y, centerPoint.x, centerPoint.y,
        // _radius)
        private boolean inCircle(float x, float y, float circleCenterX, float circleCenterY, float circleRadius) {
            double dx = Math.pow(x - circleCenterX, 2);
            double dy = Math.pow(y - circleCenterY, 2);

            if ((dx + dy) < Math.pow(circleRadius, 2)) {
                return true;
            }
            else {
                return false;
            }
        }

        /**
         * Ao apertar botao, inicia thread de mudanca de angulo Criado em 28/08/2012
         */
        private void onButtonDown() {
            if (!rotateThreadRunning)
                startRotateThread();
        }

        /**
         * Para a thread de mudança de angulo Criado em 28/08/2012
         */
        private void stopRotateThread() {
            if (rotateThreadRunning)
                cancelRotateThread = true;
        }

        /**
         * Thread de mudança de angulo Criado em 28/08/2012
         */
        private void startRotateThread() {

            Thread r = new Thread() {

                @Override
                public void run() {
                    try {

                        rotateThreadRunning = true;
                        while (!cancelRotateThread) {

                            handler.post(new Runnable() {
                                @Override
                                public void run() {
                                    if (isBtnPlus) {
                                        if (lastDegrees == -359) {
                                            setLastDegrees(0);
                                        }
                                        else {
                                            setLastDegrees(lastDegrees - 1);
                                        }
                                    }
                                    else {
                                        if (lastDegrees == 0) {
                                            setLastDegrees(-359);
                                        }
                                        else {
                                            setLastDegrees(lastDegrees + 1);
                                        }
                                    }
                                    doOnTouch(true);
                                }
                            });

                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                throw new RuntimeException("------ Problema na thread rotate ------", e);
                            }
                        }
                    } finally {
                        rotateThreadRunning = false;
                        cancelRotateThread = false;
                    }
                }
            };

            r.start();
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        }

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            thread.setRunning(true);
            thread.start();
        }

        public Panel(Context context) {
            super(context);
            getHolder().addCallback(this);
            thread = new CanvasThread(getHolder(), this);
            setFocusable(true);
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            /*
             * É preciso mandar a thread desligar e esperar até terminar, senão pode ocorrer um toque na tela e travar
             */
            boolean retry = true;
            thread.setRunning(false);
            while (retry) {
                try {
                    thread.join();
                    retry = false;
                    finish(); // termina activity
                } catch (InterruptedException e) {
                    // we will try it again and again...
                }
            }
        }
    }

    class CanvasThread extends Thread {
        /*
         * In order to draw to the Surface Canvas from within your second thread, you must pass the thread your SurfaceHandler and retrieve the Canvas with lockCanvas().
         */
        private SurfaceHolder _surfaceHolder;
        private Panel         _panel;
        private boolean       _run = false;

        public CanvasThread(SurfaceHolder surfaceHolder, Panel panel) {
            _surfaceHolder = surfaceHolder;
            _panel = panel;
        }

        @SuppressLint("WrongCall")
        @Override
        public void run() {
            Canvas canvas;
            while (_run) {
                canvas = null;
                try {
                    canvas = _surfaceHolder.lockCanvas(null);
                    synchronized (_surfaceHolder) {
                        /*
                         * You can now take the Canvas given to you by the SurfaceHolder and do your necessary drawing upon it
                         */
                        _panel.onDraw(canvas);
                    }
                } finally {
                    // do this in a finally so that if an exception is thrown
                    // during the above, we don't leave the Surface in an
                    // inconsistent state
                    if (canvas != null) {
                        /*
                         * Once you're done drawing with the Canvas, call unlockCanvasAndPost(), passing it your Canvas object. The Surface will now draw the Canvas as you left it.
                         * Perform this sequence of locking and unlocking the canvas each time you want to redraw
                         */
                        _surfaceHolder.unlockCanvasAndPost(canvas);
                    }
                }
            }
        }

        public void setRunning(boolean isRunning) {
            this._run = isRunning;
        }

        public SurfaceHolder getSurfaceHolder() {
            return this._surfaceHolder;
        }
    }

    /**
     * Convert the dips (Device independt pixels) to pixels Fica o mesmo tamanho independente da resolucao da tela
     */
    private int dipsToPixels(int dipValue) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, getResources().getDisplayMetrics());
    }

    /**
     * Fecha app
     */
    @Override
    public void onBackPressed() {
        try {
            thread.setRunning(false);
            this.finish();
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onPause() {
        thread.setRunning(false);
        super.onPause();
    }

    @Override
    protected void onResume() {
        thread.setRunning(true);
        super.onResume();
    }

}
